﻿using UnityEngine;

namespace ZXthex
{
    public sealed class CutMesh
    {
        static CutAMeshCore core;

        static CutMesh()
        {
            core = new CutAMeshCore();
        }
        
        /// <summary>
        /// 将meshFilter的mesh切成两块， 同一部分的截面（内面）和外表合并为一个Mesh
        /// </summary>
        /// <param name="meshFilter">被切的Mesh所在的MeshFilter组件</param>
        /// <param name="planePointWorld">切面上的点</param>
        /// <param name="planeNormalWorld">切面的法线</param>
        /// <param name="pieceOne">切面上的切块</param>
        /// <param name="pieceTwo">切面下的切块</param>
        /// <param name="fillUV">内面是否需要uv</param>
        /// <returns>是否将mesh切为两块</returns>
        public static bool CutAMesh(MeshFilter meshFilter, Vector3 planePointWorld, Vector3 planeNormalWorld,
                                        out Mesh pieceOne, out Mesh pieceTwo, bool fillUV = false)
        {
            return core.CutAMesh(meshFilter.mesh, meshFilter.transform, planePointWorld, planeNormalWorld,
                    out pieceOne, out pieceTwo, fillUV);
        }

        /// <summary>
        /// 将meshCollider的mesh切成两块， 同一部分的切面（内面）和外表合并为一个Mesh
        /// </summary>
        /// <param name="meshCollider">被切的Mesh所在的meshCollider组件</param>
        /// <param name="planePointWorld">切面上的点</param>
        /// <param name="planeNormalWorld">切面的法线</param>
        /// <param name="pieceOne">切面上的切块</param>
        /// <param name="pieceTwo">切面下的切块</param>
        /// <returns>是否将mesh切为两块</returns>
        public static bool CutAMesh(MeshCollider meshCollider, Vector3 planePointWorld, Vector3 planeNormalWorld,
                                       out Mesh pieceOne, out Mesh pieceTwo)
        {
            return core.CutAMesh(meshCollider.sharedMesh, meshCollider.transform, planePointWorld, planeNormalWorld,
                    out pieceOne, out pieceTwo);
        }

        /// <summary>
        /// 将物体切成两份外表Mesh pieceOne和pieceTwo，以及内面Mesh pieceOneFill和pieceTwoFill
        /// 如果物体的子物体有MeshFilter，则将其视为上一次切完后生成的内面MeshFilter
        /// 
        /// 这个方法适用于内面使用独立的贴图的情况
        /// 如果物体在被切后允许继续被切，则应将内面Mesh设为物体外表Mesh物体的子物体
        /// </summary>
        /// <param name="meshFilter">物体的最上层MeshFilter组件，即物体外表Mesh的组件</param>
        /// <param name="planePointWorld">切面上的点</param>
        /// <param name="planeNormalWorld">切面的法线</param>
        /// <param name="pieceOne">切面上的切块表面</param>
        /// <param name="pieceTwo">切面下的切块表面</param>
        /// <param name="pieceOneFill">切面上的切块切面</param>
        /// <param name="pieceTwoFill">切面下的切块切面</param>
        /// <returns>是否将mesh切为两块</returns>
        public static bool CutAMesh(MeshFilter meshFilter, Vector3 planePointWorld, Vector3 planeNormalWorld,
                                        out Mesh pieceOne, out Mesh pieceTwo, out Mesh pieceOneFill, out Mesh pieceTwoFill)
        {
            //将网格切分成
            if (core.CutAMesh(meshFilter.mesh, meshFilter.transform, planePointWorld, planeNormalWorld,
                     out pieceOne, out pieceTwo, out pieceOneFill, out pieceTwoFill, true))
            {
                var mfs = meshFilter.GetComponentsInChildren<MeshFilter>(false);
                CombineInstance[] cmbs = new CombineInstance[mfs.Length - 1];
                for (int i = 1; i < mfs.Length; i++)
                {
                    cmbs[i - 1].mesh = mfs[i].mesh;
                    cmbs[i - 1].transform = Matrix4x4.identity;
                }
                Mesh mesh = new Mesh();
                mesh.CombineMeshes(cmbs);


                core.CutAMesh(mesh, meshFilter.transform, planePointWorld, planeNormalWorld, out Mesh p1, out Mesh p2, true);

                cmbs = new CombineInstance[2];
                cmbs[0].transform = cmbs[1].transform = Matrix4x4.identity;
                if (p1?.vertexCount > 0)
                {
                    cmbs[0].mesh = pieceOneFill; cmbs[1].mesh = p1;
                    pieceOneFill = new Mesh();
                    pieceOneFill.CombineMeshes(cmbs);
                }

                if (p2?.vertexCount > 0)
                {
                    cmbs[0].mesh = pieceTwoFill; cmbs[1].mesh = p2;
                    pieceTwoFill = new Mesh();
                    pieceTwoFill.CombineMeshes(cmbs);
                }

                return true;
            }
            return false;
        }
        

    }
}
